/*
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.
 */
package erwiki.api.providers;

import java.util.Collection;
import java.util.Date;
import java.util.List;

import org.elwiki_data.AttachmentContent;
import org.elwiki_data.PageAttachment;
import org.elwiki_data.PageContent;
import org.elwiki_data.PageReference;
import org.elwiki_data.UnknownPage;
import org.elwiki_data.WikiPage;

import erwiki.api.exceptions.ProviderException;
import erwiki.api.pages.PageManager.PageMotionType;
import erwiki.api.search.QueryItem;
import erwiki.api.search.SearchResult;

/**
 * Each Wiki page provider should implement this interface.
 * <P>
 * You can build whatever page providers based on this, just leave the unused methods do something
 * useful.
 * <P>
 * WikiPageProvider uses Strings and ints to refer to pages. This may be a bit odd, since
 * WikiAttachmentProviders all use Attachment instead of name/version. We will perhaps modify these
 * in the future. In the mean time, name/version is quite sufficient.
 * <P>
 * FIXME: In reality we should have an AbstractWikiPageProvider, which would provide intelligent
 * backups for subclasses.
 */
public interface PageProvider extends WikiProvider {

	/**
	 * Ищет WikiPage по заданному имени.
	 *
	 * @param pageName Имя страницы, которую нужно найти.
	 * @return Экземпляр WikiPage или значение <code>null</code>, если требуемая страница не найдена.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	WikiPage getPageByName(String pageName) throws ProviderException;

	/**
	 * Пытается сохранить текст страницы для заданной страницы "page". Обратите внимание, что провайдер
	 * создает еще один контент страницы, с версией +1.
	 *
	 * @param page       WikiPage, в которой нужно сохранить новый текст.
	 * @param text       Текст для сохранения.
	 * @param author     Автор, вносящий новый текст.
	 * @param changenote Комментарий для нового текста.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	void putPageText(WikiPage page, String text, String author, String changenote) throws ProviderException;

	/**
	 * Saves comment text of page.
	 *
	 * @param page    The target WikiPage to save comment.
	 * @param comment Text of the comment.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	void savePageComment(WikiPage page, String comment) throws ProviderException;

	/**
	 * Return true, if page exists.
	 *
	 * @param pageId ID of the page.
	 * @return true, if page exists.
	 */
	boolean pageExistsById(String pageId);

	/**
	 * Return true, if page exists.
	 *
	 * @param page The page name.
	 * @return true, if the page exists; false otherwise.
	 */
	boolean pageExistsByName(String page);

	/**
	 * Return true, if page with a particular version exists.
	 *
	 * @param page    The page name to check for
	 * @param version The version to check
	 * @return True, if page exists; false otherwise.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	boolean pageExists(String page, int version) throws ProviderException;

	/**
	 * Finds pages based on the query. Only applicable to providers which implement the FastSearch
	 * interface. Otherwise JSPWiki will use its internal cache.
	 * <p>
	 * This method should really be a part of the FastSearch IF.
	 *
	 * @param query An array of QueryItems to match
	 * @return A Collection of WikiPages.
	 */
	Collection<SearchResult> findPages(QueryItem[] query);

	/**
	 * Returns info about the page.
	 *
	 * @return A filled WikiPage.
	 * @param page    The page name
	 * @param version The version number
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	WikiPage getPageInfo(String page, int version) throws ProviderException;

	/**
	 * Returns only of upper level pages.
	 *
	 * @return A collection of upper level WikiPages.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	Collection<WikiPage> getUpperPages() throws ProviderException;

	/**
	 * Returns all pages. Each element in the returned Collection should be a WikiPage.
	 *
	 * @return A collection of WikiPages
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	Collection<WikiPage> getAllPages() throws ProviderException;

	/**
	 * Gets a list of recent changes.
	 *
	 * @param date The date to check from
	 * @return A Collection of WikiPages
	 */
	Collection<WikiPage> getAllChangedSince(Date date);

	/**
	 * Gets the number of pages.
	 *
	 * @return The number of pages in the repository
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	int getPageCount() throws ProviderException;

	/**
	 * Returns version history. Each element should be a WikiPage.
	 *
	 * @param page The name of the page to get the history from.
	 * @return A collection of WikiPages.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	@Deprecated
	List<PageContent> getVersionHistory(WikiPage page) throws ProviderException;

	/**
	 * Gets a specific version out of the repository.
	 *
	 * @param page    Name of the page to fetch.
	 * @param version Version of the page to fetch.
	 * @return The content of the page, or null, if the page does not exist.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	String getPageText(String page, int version) throws ProviderException;

	/**
	 * Removes a specific version from the repository. The implementations should really do no more
	 * security checks, since that is the domain of the PageManager. Just delete it as efficiently as
	 * you can.
	 *
	 * @param pageName Name of the page to be removed.
	 * @param version  Version of the page to be removed. May be LATEST_VERSION.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	void deleteVersion(String pageName, int version) throws ProviderException;

	/**
	 * Удаляет всю страницу из репозитория.
	 * <p>
	 * Реализация действительно не должна обеспечивать дополнительную проверку безопасности, поскольку
	 * это задача AttachmentManager. </br>
	 * Просто удалите ее как можно эффективнее. Вам также следует удалить все вспомогательные файлы,
	 * принадлежащие этой странице, ЕСЛИ они были созданы этим провайдером.
	 *
	 * Removes an entire page from the repository. The implementations should really do no more security
	 * checks, since that is the domain of the PageManager. Just delete it as efficiently as you can.
	 * You should also delete any auxiliary files that belong to this page, IF they were created by this
	 * provider.
	 *
	 * <p>
	 *
	 * <p>
	 * Return operation status: =true - page removed successfully; =false - something went wrong.
	 *
	 * @param wikiPage Name of the page to be removed completely.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	void deletePage(WikiPage wikiPage) throws ProviderException;

	/**
	 * Move a page
	 *
	 * @param from Name of the page to move.
	 * @param to   New name of the page.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	void movePage(String from, String to) throws ProviderException;

	/**
	 * Returns the page corresponding to the page ID.
	 *
	 * @param pageId ID of the required page.
	 * @return Wiki page or <code>null</code>.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	WikiPage getPageById(String pageId) throws ProviderException;

	String getMainPageId();

	/**
	 * Creates new wiki page.</br>
	 * If the parent page is set to null, then the page is created in the wiki root.
	 *
	 * @param name       The name of page.
	 * @param content    The content of page.
	 * @param parentPage Parent page of new page.
	 * @return New wiki page.
	 */
	WikiPage createPage(String name, String content, WikiPage parentPage);

	/**
	 * Add attachment metadata for specisied wiki page.</br>
	 * If the operation is successful, also increases the attachments ID of data model.
	 *
	 * @param wikiPage   specified page.
	 * @param attContent new metadata of attachment.
	 * @param attName    name of attachment.
	 */
	void addAttachment(WikiPage wikiPage, AttachmentContent attContent, String attName) throws Exception;

	/**
	 * Returns the PageAttachment corresponding to the page attachment ID.
	 *
	 * @param pageAttachmentId page attachment ID.
	 * @return
	 * @throws Exception если что-то пошло не так, как ожидалось.
	 */
	PageAttachment getPageAttachmentById(String pageAttachmentId) throws Exception;

	void updateReferences(WikiPage page, Collection<String> pagesIds, Collection<String> unknownPages)
			throws ProviderException;

	/**
	 * Finds all references that refer to this page. Returns a collection containing
	 * {@link PageReference} that refer to this one.</br>
	 * The page version is not taken into account.
	 * <p>
	 *
	 * @param pageId The page ID to find referrers for.
	 * @return A List of {@link PageReference}. May return empty, if it has no references.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	List<PageReference> getPageReferrers(String pageId) throws ProviderException;

	List<UnknownPage> getUnknownPages() throws ProviderException;

	/**
	 * Returns a collection of pages that are not linked to in other pages.
	 *
	 * @return Collection of pages that are not linked to in other pages.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	Collection<PageReference> getPageReferences() throws ProviderException;

	/**
	 * Moves the page.
	 *
	 * @param motionType
	 * @param targetPageId
	 * @param movedPageId
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	void movePage(PageMotionType motionType, String targetPageId, String movedPageId) throws ProviderException;

	void setPageTimestamp(WikiPage wikiPage, Date time);

	void renamePage(String newName, WikiPage renamedPage1);

	List<WikiPage> getRootPages();

	void changeHierarchy(WikiPage master1, List<WikiPage> children);

	/**
	 * Задает идентификатор страницы (где он пуст).
	 *
	 * @throws ProviderException
	 */
	void fvkPagesIdAdjust() throws ProviderException;

	/**
	 * Изменить ссылки между страницами, согласно по ссылкам содержимого страниц.
	 *
	 * @see org.elwiki.api.pageprovider.IWikiPageProvider#fvkPagesRefreshReferences()
	 *
	 * @throws ProviderException
	 */
	void fvkPagesRefreshReferences() throws ProviderException;

}
